//*******************************************************************       //
//IMPORTANT NOTICE                                                          //
//================                                                          //
//Copyright Mentor Graphics Corporation 1996 - 1999.  All rights reserved.  //
//This file and associated deliverables are the trade secrets,              //
//confidential information and copyrighted works of Mentor Graphics         //
//Corporation and its licensors and are subject to your license agreement   //
//with Mentor Graphics Corporation.                                         //
//                                                                          //
//Use of these deliverables for the purpose of making silicon from an IC    //
//design is limited to the terms and conditions of your license agreement   //
//with Mentor Graphics If you have further questions please contact Mentor  //
//Graphics Customer Support.                                                //
//                                                                          //
//This Mentor Graphics core (m8051w v2002.080) was extracted on             //
//workstation hostid 8316cbec Inventra                                      //
// Timer Counters for M8051W/EW
// 
// $Log: m3s017dy.v,v $
// Revision 1.7  2002/01/09
// first clean Verilog for version 2
//
// Revision 1.6  2001/11/20
// First checkin of version 2 features and name change
//
// Revision 1.2  2001/10/31
// First parsable verilog for EW
//
// Revision 1.1.1.1  2001/07/17
// Re-imported E-Warp from Farnham filesystem
//
// Revision 1.5  2000/10/24
// Multiplier rewritten to improve power consumption.
// Code changes for Leonardo (ECN01372).
// Code changes for formal verification tools (ECN01410).
// MOVX @Ri page address controllable from PORT2I if I/O ports ommitted (ECN01387).
//
// Revision 1.4  2000/02/20
// NINT0/1 sampling and condition zero ALU timing optimisation
//
// Revision 1.3  2000/02/05
// Name change repercussions
//
// Revision 1.2  1999/12/08
// Eliminate user instruction during state transition from interrupt service to
// debug state.
// RTL clean up of redundant declarations and sensitvity list entries.
//
// Revision 1.1.1.1  1999/10/28
// "initialization and source check-in for m8051e"
//
// Revision 1.1  1999/10/22
// Initial revision
//
////////////////////////////////////////////////////////////////////////////////

`include "m8051w_defs.v"

module m3s017dy (TIMER_SFR_DATA, IE0, TF0, IE1, TF1, T1_OVERFLOW, TF2,
//*******************************************************************       //
//IMPORTANT NOTICE                                                          //
//================                                                          //
//Copyright Mentor Graphics Corporation 1996 - 1999.  All rights reserved.  //
//This file and associated deliverables are the trade secrets,              //
//confidential information and copyrighted works of Mentor Graphics         //
//Corporation and its licensors and are subject to your license agreement   //
//with Mentor Graphics Corporation.                                         //
//                                                                          //
//Use of these deliverables for the purpose of making silicon from an IC    //
//design is limited to the terms and conditions of your license agreement   //
//with Mentor Graphics If you have further questions please contact Mentor  //
//Graphics Customer Support.                                                //
//                                                                          //
//This Mentor Graphics core (m8051w v2002.080) was extracted on             //
//workstation hostid 8316cbec Inventra                                      //
                 T2_OVERFLOW, T2_TCLK, T2_RCLK, SFRSA, DESTIN_ADDR, SFRWE,
                 REG_RESULT, INTR_ACKNOW, PORT1I, PORT3I,
                 RMW, INTERNAL_RESET, INTERNAL_WAIT, PCLK_EN, SCLK, CCLK, PCLK);

  output [7:0] TIMER_SFR_DATA;
  output       IE0, TF0, IE1, TF1, TF2;
  output       T1_OVERFLOW;
  output       T2_OVERFLOW;
  output       T2_TCLK;
  output       T2_RCLK;

  input  [7:0] REG_RESULT;
  input  [6:0] SFRSA;
  input  [6:0] DESTIN_ADDR;
  input  [3:0] INTR_ACKNOW;
  input  [5:2] PORT3I;
  input  [1:0] PORT1I;

  input        SFRWE, RMW, INTERNAL_RESET;
  input        INTERNAL_WAIT;
  input        PCLK_EN;
  input        SCLK, CCLK, PCLK;

  reg    [7:0] I_TCON, TMOD;                         // Timer/Counter SFRs
  reg    [5:2] PORT_3_SAMPLE_P1;                     // Port 3 sampler registers
  reg    [5:2] PORT_3_SAMPLE_P2;                     // Port 3 sampler registers
  reg    [5:4] LAST_PORT_3_SAMPLE_P2;                // Edge detectors
  reg    [1:0] PORT_1_SAMPLE_P2;                     // Port 3 sampler registers
  reg    [1:0] LAST_PORT_1_SAMPLE_P2;                // Edge detectors
  reg    [7:0] T2CON;                                // Timer/Counter 2 SFRs
  reg    [7:0] RCP2L, RCP2H;

  wire   [7:0] TIMER_SFR_DATA;                       // Multiplexed SFR data
  wire   [7:0] T2_SFR_DATA;                          // data multiplex
  wire   [7:0] TCON;                                 // Timer/Counter SFRs
  wire   [7:0] TL0, TH0, TL1, TH1;                   // Timer/Counter SFRs
  wire   [7:0] TL2, TH2;
  wire         TL0_CARRY, TL1_CARRY;                 // Counter Carry Outputs
  wire         TH0_CARRY, TH1_CARRY;
  wire         TL2_CARRY, TH2_CARRY;                 // Timer 2 carry outputs
  wire         TL0_CARRY_IN, TL1_CARRY_IN;           // Counter Carry Inputs
  wire         TH0_CARRY_IN, TH1_CARRY_IN;
  wire         T0_MODE0, T1_MODE0;                   // Mode 0 Decodes
  wire         TL0_LOAD, TL1_LOAD;                   // Low byte load controls
  wire         TL2_LOAD, TH2_LOAD;                   // Timer 2 load controls
  wire         TL0_EN, TH0_EN, T1_EN, T2_EN;         // Counter clock qualifiers
  wire   [7:0] TL0_DATA, TL1_DATA;                   // Multiplexed load data
  wire   [7:0] TL2_DATA, TH2_DATA;                   // Multiplexed load data
  wire         TCON_WRITE, TMOD_WRITE;               // SFR write qualifiers
  wire         TL0_WRITE, TL1_WRITE;
  wire         TH0_WRITE, TH1_WRITE;
  wire         TL2_WRITE, TH2_WRITE;
  wire         T2CON_WRITE;
  wire         RCP2L_WRITE, RCP2H_WRITE;
  wire         T0_OVERFLOW, T1_OVERFLOW;             // Counter overflow outputs
  wire         IE0_EDGE, IE1_EDGE;                   // Interrupt edge detects
  wire         T0_COUNT, T1_COUNT, T2_COUNT;         // Count edge detects
  wire         T2BAUDM, T2CAPTURE, T2RELOAD;         // timer 2 modes
  wire         NXT_EXF2;                             // next state for EXF2
  wire         IE0, TF0, IE1, TF1;                   // Interrupt outputs

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Instantiate Four Eight-bit Counters                                        //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  // Timer 0 Low Byte
  m3s016dy uTL0(.CARRY_OUT(TL0_CARRY), .COUNT(TL0), .MODE0(T0_MODE0),
                .LOAD(TL0_LOAD), .CARRY_IN(TL0_CARRY_IN), .COUNT_EN(TL0_EN),
                .DATA_IN(TL0_DATA), .INT_RESET(INTERNAL_RESET), .PCLK(PCLK));

  // Timer 0 High Byte
  m3s016dy uTH0(.CARRY_OUT(TH0_CARRY), .COUNT(TH0), .MODE0(1'b0),
                .LOAD(TH0_WRITE), .CARRY_IN(TH0_CARRY_IN), .COUNT_EN(TH0_EN),
                .DATA_IN(REG_RESULT), .INT_RESET(INTERNAL_RESET), .PCLK(PCLK));

  // Timer 1 Low Byte
  m3s016dy uTL1(.CARRY_OUT(TL1_CARRY), .COUNT(TL1), .MODE0(T1_MODE0),
                .LOAD(TL1_LOAD), .CARRY_IN(TL1_CARRY_IN), .COUNT_EN(T1_EN),
                .DATA_IN(TL1_DATA), .INT_RESET(INTERNAL_RESET), .PCLK(PCLK));

  // Timer 1 High Byte
  m3s016dy uTH1(.CARRY_OUT(TH1_CARRY), .COUNT(TH1), .MODE0(1'b0),
                .LOAD(TH1_WRITE), .CARRY_IN(TH1_CARRY_IN), .COUNT_EN(T1_EN),
                .DATA_IN(REG_RESULT), .INT_RESET(INTERNAL_RESET), .PCLK(PCLK));

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// TCON and TMOD Register Interface                                           //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  assign TCON_WRITE = SFRWE && DESTIN_ADDR[6:0] == `AddrTCON;
  assign TMOD_WRITE = SFRWE && DESTIN_ADDR[6:0] == `AddrTMOD;
  assign TL0_WRITE  = SFRWE && DESTIN_ADDR[6:0] == `AddrTL0;
  assign TL1_WRITE  = SFRWE && DESTIN_ADDR[6:0] == `AddrTL1;
  assign TH0_WRITE  = SFRWE && DESTIN_ADDR[6:0] == `AddrTH0;
  assign TH1_WRITE  = SFRWE && DESTIN_ADDR[6:0] == `AddrTH1;

  // Timer Counter Special Function Registers
  // These registers run on the CPU clock
  always @(posedge CCLK)
  begin: p_timer_SFRs
    if (INTERNAL_RESET) begin
      TMOD    <= 8'h00;
      I_TCON[0] <= 1'b0;
      I_TCON[2] <= 1'b0;
      I_TCON[4] <= 1'b0;
      I_TCON[6] <= 1'b0;
    end
    else if (TMOD_WRITE)
        TMOD    <= REG_RESULT;
      else if (TCON_WRITE) begin
        I_TCON[0] <= REG_RESULT[0];
        I_TCON[2] <= REG_RESULT[2];
        I_TCON[4] <= REG_RESULT[4];
        I_TCON[6] <= REG_RESULT[6];
      end
  end

  // TCON Interrupt Registers
  // These registers run on the peripheral clock
  // Precedence for writes is 1: Interrupt Acknowledge
  //                          2: SFR access which is not a read-modify-write;
  //                          3: Interrupt source 
  //                          4: Read-modify-write SFR access

  always @(posedge PCLK)
  begin: p_interrupt_SFRs
    if (INTERNAL_RESET) begin
      I_TCON[1] <= 1'b0;
      I_TCON[3] <= 1'b0;
      I_TCON[5]  <= 1'b0;
      I_TCON[7]  <= 1'b0;
    end
    else if (PCLK_EN) begin
      if (INTR_ACKNOW[0] && ~INTERNAL_WAIT)
        I_TCON[1] <= 1'b0;
      else if (IE0_EDGE && (RMW || !TCON_WRITE))
        I_TCON[1] <= 1'b1;
      else if (TCON_WRITE)
        I_TCON[1] <= REG_RESULT[1];

      if (INTR_ACKNOW[2] && ~INTERNAL_WAIT)
        I_TCON[3] <= 1'b0;
      else if (IE1_EDGE && (RMW || !TCON_WRITE))
        I_TCON[3] <= 1'b1;
      else if (TCON_WRITE)
        I_TCON[3] <= REG_RESULT[3];

      if (INTR_ACKNOW[1] && ~INTERNAL_WAIT)
        I_TCON[5] <= 1'b0;
      else if (T0_OVERFLOW && (RMW || !TCON_WRITE))
        I_TCON[5] <= 1'b1;
      else if (TCON_WRITE)
        I_TCON[5] <= REG_RESULT[5];

      if (INTR_ACKNOW[3] && ~INTERNAL_WAIT)
        I_TCON[7] <= 1'b0;
      else if (T1_OVERFLOW && (RMW || !TCON_WRITE))
        I_TCON[7] <= 1'b1;
      else if (TCON_WRITE)
        I_TCON[7] <= REG_RESULT[7];
    end
  end

  // Timer Counter SFR multiplexer

  assign TIMER_SFR_DATA = TCON & {8{SFRSA == `AddrTCON}}                       |
                          TMOD & {8{SFRSA == `AddrTMOD}}                       |
                          TL0  & {8{SFRSA == `AddrTL0 }}                       |
                          TL1  & {8{SFRSA == `AddrTL1 }}                       |
                          TH0  & {8{SFRSA == `AddrTH0 }}                       |
                          TH1  & {8{SFRSA == `AddrTH1 }}                       |
                          T2_SFR_DATA;

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Counter Control Logic                                                      //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  // Timer Clock Source Multiplexers
  assign TL0_EN = PCLK_EN && (!TMOD[2] || T0_COUNT);
  assign TH0_EN = PCLK_EN && (!TMOD[2] || T0_COUNT || TMOD[1:0] == 3);
  assign T1_EN  = PCLK_EN && (!TMOD[6] || T1_COUNT) && ~&TMOD[5:4];

  // Low byte carry output from bit 5 switch for counter sub-modules
  assign T0_MODE0 = ~|TMOD[1:0];
  assign T1_MODE0 = ~|TMOD[5:4];

  // Carry Inputs (timer/counter run controls)
  // high byte timer/counters do not count in modes 2 and 3 except TH0 in mode 3
  // These paths are not qualified with state timing for performance.

  assign TL0_CARRY_IN = TCON[4] && (!TMOD[3] || PORT_3_SAMPLE_P2[2]);
  assign TL1_CARRY_IN = TCON[6] && (!TMOD[7] || PORT_3_SAMPLE_P2[3]);
  assign TH0_CARRY_IN = TMOD[1]? TMOD[0] && TCON[6]: TL0_CARRY;
  assign TH1_CARRY_IN = !TMOD[5] && TL1_CARRY;

  // Timer SFR Load Controls, low bytes can auto re-load on rollover in mode 2.
  assign TL0_LOAD  = TL0_WRITE || (TMOD[1:0] == 2 && TL0_CARRY && PCLK_EN &&
                                                        (!TMOD[2] || T0_COUNT));
  assign TL1_LOAD  = TL1_WRITE || (TMOD[5:4] == 2 && TL1_CARRY && PCLK_EN &&
                                                        (!TMOD[6] || T1_COUNT));

  // Low Byte Reload Data Multiplexers for Mode 2.
  assign TL0_DATA  = TL0_WRITE? REG_RESULT: TH0;
  assign TL1_DATA  = TL1_WRITE? REG_RESULT: TH1;

  // Rollover Source Multiplexers
  // In modes 0 and 1 rollovers (TFis) originate from the high byte carry outs,
  // in mode 2 from the low byte carry outputs, and in mode 3 timer 0 sources
  // both rollovers.

  assign T0_OVERFLOW = TMOD[1]? TL0_CARRY && TL0_EN: TH0_CARRY && TH0_EN;
  assign T1_OVERFLOW = &TMOD[1:0]? TH0_CARRY && TH0_EN:
                                   T1_EN && (TMOD[5]? TL1_CARRY: TH1_CARRY);

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Interrupt and external clock input synchronisation and edge detection      //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  always @(posedge SCLK)
  begin: p_phase1_port3_samplers
      PORT_3_SAMPLE_P1 <= PORT3I;
  end

  always @(posedge PCLK)
  begin: p_phase2_port3_samplers
    if (PCLK_EN) begin
      PORT_3_SAMPLE_P2 <= PORT_3_SAMPLE_P1;
      LAST_PORT_3_SAMPLE_P2 <= PORT_3_SAMPLE_P2[5:4];
    end
  end

  assign IE0_EDGE = !PORT_3_SAMPLE_P1[2] && PORT_3_SAMPLE_P2[2];
  assign IE1_EDGE = !PORT_3_SAMPLE_P1[3] && PORT_3_SAMPLE_P2[3];
  assign T0_COUNT = !PORT_3_SAMPLE_P2[4] && LAST_PORT_3_SAMPLE_P2[4];
  assign T1_COUNT = !PORT_3_SAMPLE_P2[5] && LAST_PORT_3_SAMPLE_P2[5];

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Make interrupt sources visible at module boundary                          //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  assign TCON = {I_TCON[7:4],
                 (I_TCON[2]? I_TCON[3]: !PORT_3_SAMPLE_P2[3]), I_TCON[2],
                 (I_TCON[0]? I_TCON[1]: !PORT_3_SAMPLE_P2[2]), I_TCON[0]};
  assign IE0 = TCON[1];
  assign IE1 = TCON[3];
  assign TF0 = TCON[5];
  assign TF1 = TCON[7];

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Instantiate an Optional Timer 2                                            //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

`ifdef ExcludeTimer2

  assign TF2         = 0;
  assign T2_OVERFLOW = 0;
  assign T2_TCLK     = 0;
  assign T2_RCLK     = 0;
  assign T2_SFR_DATA = 0;

`else

  // Timer 2 Low Byte
  m3s016dy uTL2(.CARRY_OUT(TL2_CARRY), .COUNT(TL2), .MODE0(1'b0),
                .LOAD(TL2_LOAD), .CARRY_IN(T2CON[2]), .COUNT_EN(T2_EN),
                .DATA_IN(TL2_DATA), .INT_RESET(INTERNAL_RESET), .PCLK(PCLK));

  // Timer 2 High Byte
  m3s016dy uTH2(.CARRY_OUT(TH2_CARRY), .COUNT(TH2), .MODE0(1'b0),
                .LOAD(TH2_LOAD), .CARRY_IN(TL2_CARRY), .COUNT_EN(T2_EN),
                .DATA_IN(TH2_DATA), .INT_RESET(INTERNAL_RESET), .PCLK(PCLK));

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// T2CON and Capture Register Interface                                       //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  assign T2CON_WRITE = SFRWE && DESTIN_ADDR[6:0] == `AddrT2CON;
  assign TL2_WRITE   = SFRWE && DESTIN_ADDR[6:0] == `AddrTL2;
  assign TH2_WRITE   = SFRWE && DESTIN_ADDR[6:0] == `AddrTH2;
  assign RCP2L_WRITE = SFRWE && DESTIN_ADDR[6:0] == `AddrRCP2L;
  assign RCP2H_WRITE = SFRWE && DESTIN_ADDR[6:0] == `AddrRCP2H;

  always @(posedge CCLK)
  begin: p_T2CONc_SFR
    if (INTERNAL_RESET) begin
      T2CON[5:0] <= 6'h00;
      end
    else if (T2CON_WRITE) begin
      T2CON[5:0] <= REG_RESULT[5:0];
    end
  end

  always @(posedge PCLK)
  begin: p_T2CONp_SFR
    if (INTERNAL_RESET) begin
      T2CON[7:6] <= 2'b00;
      RCP2L      <= 0;
      RCP2H      <= 0;
    end
    else begin
      if  (T2_OVERFLOW && !T2BAUDM && PCLK_EN && (RMW || !T2CON_WRITE))
        T2CON[7] <= 1'b1;
      else if (T2CON_WRITE) T2CON[7] <= REG_RESULT[7];
      if  (NXT_EXF2 && (RMW || !T2CON_WRITE))
        T2CON[6] <= 1'b1;
      else if (T2CON_WRITE) T2CON[6] <= REG_RESULT[6];
      if (RCP2L_WRITE) RCP2L <= REG_RESULT;
      else if (T2CAPTURE) RCP2L <= TL2;
      if (RCP2H_WRITE) RCP2H <= REG_RESULT;
      else if (T2CAPTURE) RCP2H <= TH2;
    end
  end

// Timer 2 SFR multiplexer

  assign T2_SFR_DATA = T2CON & {8{SFRSA == `AddrT2CON}}                        |
                       TL2   & {8{SFRSA == `AddrTL2}}                          |
                       TH2   & {8{SFRSA == `AddrTH2}}                          |
                       RCP2L & {8{SFRSA == `AddrRCP2L}}                        |
                       RCP2H & {8{SFRSA == `AddrRCP2H}};

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Timer 2: Counter control                                                   //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  assign T2BAUDM     = |T2CON[5:4];
  assign T2RELOAD    = T2_OVERFLOW && PCLK_EN && (T2BAUDM || !T2CON[0])       ||
                       NXT_EXF2 && !T2BAUDM && !T2CON[0];
  assign TL2_LOAD    = TL2_WRITE || T2RELOAD;
  assign TH2_LOAD    = TH2_WRITE || T2RELOAD;
  assign T2CAPTURE   = NXT_EXF2 && !T2BAUDM && T2CON[0];
  assign TL2_DATA    = TL2_WRITE? REG_RESULT: RCP2L;
  assign TH2_DATA    = TH2_WRITE? REG_RESULT: RCP2H;
  assign T2_EN       = PCLK_EN && (!T2CON[1] || T2_COUNT);
  assign T2_OVERFLOW = TH2_CARRY && (!T2CON[1] || T2_COUNT);

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Timer 2: Interrupt and external clock synchronisation and edge detection   //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  always @(posedge PCLK)
  begin: p_phase2_port1_samplers
    if (PCLK_EN) begin
      PORT_1_SAMPLE_P2      <= PORT1I;
      LAST_PORT_1_SAMPLE_P2 <= PORT_1_SAMPLE_P2;
    end
  end

  assign T2_COUNT = !PORT_1_SAMPLE_P2[0] & LAST_PORT_1_SAMPLE_P2[0];
  assign NXT_EXF2 = !PORT_1_SAMPLE_P2[1] & LAST_PORT_1_SAMPLE_P2[1] & T2CON[3];

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Timer 2: Make interrupt sources and budrate mode visible                   //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

  assign TF2     = |T2CON[7:6] || (T2_OVERFLOW && !T2BAUDM) || NXT_EXF2;
  assign T2_TCLK = T2CON[4];
  assign T2_RCLK = T2CON[5];

`endif
endmodule
